<?php

namespace C\S\Other;

use C\L\Service;
use C\M\Message as MessageModel;
use C\M\MessageLog as MessageLogModel;
use C\M\User as UserModel;
use Phalcon\Mvc\Model\Query;

class Message extends Service
{
    protected function setModel()
    {
        $this->model = new \C\M\Message();
    }

    /**
     * 对用户使用模版发送消息
     *
     * @param int $userId
     * @param string $templateType
     * @param string $title
     * @param string $content
     * @return bool
     **/
    public function sendMessageToUser($userId, $templateType, $params)
    {
        $templates = $this->di['config']->get('message-template')->toArray();
        $template = $templates[$templateType];
        if (!$template) {
            throw new \Exception('无通知模版');
        }

        $content = array_reduce(
            array_keys($params),
            function ($result, $key) use ($params) {
                return str_replace($key, $params[$key], $result);
            },
            $template['content']
        );

        return $this->create($userId, 'user', $template['title'], $content);
    }

    /**
     * 创建站内信
     *
     * @param int $messageableId
     * @param string $messageableType
     * @param string $title
     * @param string $content
     * @return bool
     **/
    public function create($messageableId, $messageableType, $title, $content)
    {
        $message = new MessageModel;
        $message->messageable_id = $messageableId;
        $message->messageable_type = $messageableType;
        $message->title = $title;
        $message->content = $content;

        $result = $message->save();

        if (!$result) {
            throw new \Exception('创建消息失败');
        }

        return true;
    }

    /**
     * 更新站内信
     *
     * @param int $id
     * @param int $messageableId
     * @param string $messageableType
     * @param string $title
     * @param string $content
     * @return bool
     **/
    public function newUpdate($id, $messageableId, $messageableType, $title, $content)
    {
        $message = MessageModel::findById($id);
        $message->messageable_id = $messageableId;
        $message->messageable_type = $messageableType;
        $message->title = $title;
        $message->content = $content;

        $result = $message->save();

        if (!$result) {
            throw new \Exception('创建消息失败');
        }

        return true;
    }

    /**
     * 删除站内信
     *
     * @param int $id
     * @return bool
     **/
    public function delete($id)
    {
        $message = MessageModel::findById($id);
        if (!$message) {
            throw new \Exception('未找到该消息');
        }

        return $message->delete();
    }

    /**
     * 列出用户的站内信
     *
     * @param int $userId
     * @param int $page
     * @param int $perPage
     * @return array
     **/
    public function listUserMessages($userId, $page = 1, $perPage = 15)
    {
        $user = UserModel::findById($userId);
        if (!$user) {
            throw new \Exception('未找到该用户');
        }
        $level = $this->di['s_level']->getLevel($userId);

        $phql = "
            SELECT messages.*, COALESCE(message_logs.state, 'sent') AS state
            FROM C\M\Message AS messages
            LEFT JOIN C\M\MessageLog AS message_logs 
            ON messages.id = message_logs.message_id AND message_logs.user_id = :user_id:
            WHERE
            (
              (messages.messageable_type = 'all') OR
              (messages.messageable_type = 'user' AND messages.messageable_id = :user_id:) OR
              (messages.messageable_type = 'level' AND messages.messageable_id = :level_id:)
            )
            AND messages.created_at >= :user_create_time:
            AND (message_logs.state != 'deleted' OR message_logs.state IS NULL)
            ORDER BY messages.id DESC
            LIMIT {limit:int} OFFSET {offset:int}
        ";

        $query = new Query($phql, $this->getDi());
        $result = $query->execute([
            'user_id'          => $userId,
            'level_id'         => $level['id'],
            'user_create_time' => date('Y-m-d H:i:s', $user->addtime),
            'limit'            => $perPage,
            'offset'           => $perPage * ($page - 1),
        ]);

        return array_map(
            function ($item) {
                $message = $item->messages->toArray();
                $message['state'] = $item->state;
                return $message;
            },
            $result->toArray()
        );
    }

    /**
     * 统计未读站内信数量
     *
     * @param int $userId
     * @return int
     **/
    public function countUserUnreadMessages($userId)
    {
        $user = UserModel::findById($userId);
        if (!$user) {
            throw new \Exception('未找到该用户');
        }
        $level = $this->di['s_level']->getLevel($userId);

        $phql = "
            SELECT COUNT(*) FROM C\M\Message AS messages
            LEFT JOIN C\M\MessageLog AS message_logs 
            ON messages.id = message_logs.message_id AND message_logs.user_id = :user_id:
            WHERE
            (
              (messages.messageable_type = 'all') OR
              (messages.messageable_type = 'user' AND messages.messageable_id = :user_id:) OR
              (messages.messageable_type = 'level' AND messages.messageable_id = :level_id:)
            )
            AND messages.created_at >= :user_create_time:
            AND (message_logs.state = 'sent' OR message_logs.state IS NULL)
        ";


        $query = new Query($phql, $this->getDi());

        $result = $query->getSingleResult([
            'user_id'          => $userId,
            'level_id'         => $level['id'],
            'user_create_time' => date('Y-m-d H:i:s', $user->addtime),
        ]);

        return (int)$result->toArray()[0] ?? 0;
    }

    /**
     * 阅读站内信
     *
     * @param int $userId
     * @param int $messageId
     * @return int
     **/
    public function read($userId, $messageId)
    {
        $messageLog = $this->getMessageLog($userId, $messageId);
        if (!$messageLog) {
            $messageLog = new MessageLogModel;
        }

        $messageLog->user_id = $userId;
        $messageLog->message_id = $messageId;
        $messageLog->state = 'read';

        return $messageLog->save();
    }

    /**
     * 未阅读站内信
     *
     * @param int $userId
     * @param int $messageId
     * @return int
     **/
    public function unread($userId, $messageId)
    {
        $messageLog = $this->getMessageLog($userId, $messageId);
        if (!$messageLog) {
            $messageLog = new MessageLogModel;
        }

        $messageLog->user_id = $userId;
        $messageLog->message_id = $messageId;
        $messageLog->state = 'sent';

        return $messageLog->save();
    }

    /**
     * 删除站内信
     *
     * @param int $userId
     * @param int $messageId
     * @return int
     **/
    public function deleteLog($userId, $messageId)
    {
        $messageLog = $this->getMessageLog($userId, $messageId);
        if (!$messageLog) {
            $messageLog = new MessageLogModel;
        }

        $messageLog->user_id = $userId;
        $messageLog->message_id = $messageId;
        $messageLog->state = 'deleted';

        return $messageLog->save();
    }

    /**
     * 是否有新消息
     *
     * @param int $userId
     * @return bool
     **/
    public function hasNewMessage($userId)
    {
        $user = UserModel::findById($userId);
        if (!$user) {
            throw new \Exception('未找到该用户');
        }
        $level = $this->di['s_level']->getLevel($userId);
        $latestMessageId = $user->notice_id;

        $phql = "" .
        "SELECT messages.id " .
        "FROM C\M\Message AS messages " .
        "LEFT JOIN C\M\MessageLog AS message_logs ON messages.id = message_logs.message_id " .
        "WHERE " .
        "(messages.id > :latest_message_id:) AND " .
        "(messages.created_at >= :user_create_time:) AND " .
        "(message_logs.user_id = :user_id: OR message_logs.user_id IS NULL) AND " .
        "(message_logs.state IS NULL OR message_logs.state = 'sent') AND " .
        "(" .
        "  (messages.messageable_type = 'all') OR " .
        "  (messages.messageable_type = 'user' AND messages.messageable_id = :user_id:) OR " .
        "  (messages.messageable_type = 'level' AND messages.messageable_id = :level_id:) " .
        ") " .
        "ORDER BY messages.id DESC " .
        "LIMIT 1";

        $query = new Query($phql, $this->getDi());

        $result = $query->getSingleResult([
            'user_id'           => $userId,
            'level_id'          => $level['id'],
            'user_create_time'  => date('Y-m-d H:i:s', $user->addtime),
            'latest_message_id' => $latestMessageId,
        ]);

        if (!$result) {
            return false;
        }

        $this->di['s_user']->update($userId, ['notice_id' => $result['id']]);

        return true;
    }

      /**
       * 发送注册信息
       *
       * @param int $userId
       * @return bool
       **/
    public function sendRegisterMessageToUser($userId)
    {
        $config = $this->di['s_config']->get('message_settings') ?? [];
        $registerMessageConfig = $config['register'] ?? [];
        
        $status = $registerMessageConfig['status'] ?? false;
        if (!$status) {
            return false;
        }
        
        $this->create(
            $userId,
            'user',
            $registerMessageConfig['title'] ?? '',
            $registerMessageConfig['content'] ?? ''
        );
    }

    /**
     * 获取站内信记录
     *
     * @param int $userId
     * @param int $messageId
     * @return int
     **/
    private function getMessageLog($userId, $messageId)
    {
        $conditions = 'user_id = :user_id: AND message_id = :message_id:';
        $bind = [
            'user_id'    => $userId,
            'message_id' => $messageId,
        ];

        return MessageLogModel::findFirst(compact('conditions', 'bind'));
    }
}
